package jamirr;

import java.util.*;
import java.util.stream.Collectors;

class AnnotatedElementImpl implements AnnotatedElement {

    private final Map<String, AnnotationMirror> declaredAnnotations;
    private Map<String, AnnotationMirror> annotations;

    public AnnotatedElementImpl(AnnotationMirror[] declaredAnnotations) {
        this.declaredAnnotations = Arrays.stream(declaredAnnotations)
                .map(a -> Map.entry(a.getName(), a))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    @Override
    public Map<String, AnnotationMirror> getDeclaredAnnotations() {
        return declaredAnnotations;
    }

    @Override
    public Map<String, AnnotationMirror> getAnnotations() {
        if (annotations == null) {
            annotations = new LinkedHashMap<>();
            declaredAnnotations.values()
                    .forEach(a -> {
                        this.annotations.putAll(a.getAnnotations());
                        if (!this.annotations.containsKey(a.getName())) {
                            this.annotations.put(a.getName(), a);
                        }
                    });
        }
        return Collections.unmodifiableMap(annotations);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T getAnnotationValue(String annotation, String attribute) {
        if (!hasAnnotation(annotation)) {
            return null;
        }
        boolean begin = false;
        Collection<AnnotationMirror> values = getAnnotations().values();
        String annotationName = annotation;
        String memberName = attribute;
        AnnotationAttribute<?> lastAttr = null;
        for (AnnotationMirror a : values) {
            if (a.getName().equals(annotation)) {
                AnnotationAttribute<?> m = a.getAttributes().get(attribute);
                if (m == null) {
                    return null;
                }
                Object value = m.getValue();
                if (value == null) {
                    lastAttr = m;
                    // 找同级@AliasFor注解
                    for (AnnotationAttribute<?> am : a.getAttributes().values()) {
                        if (attribute.equals(am.getAliasFor())
                                && (annotation.equals(am.getAliasForAnnotation()) || am.getAliasForAnnotation() == null)) {
                            value = am.getValue();
                            if (value == null) {
                                lastAttr = am;
                            } else {
                                return (T) value;
                            }
                        }
                    }
                    begin = true;
                    continue;
                } else {
                    return (T) value;
                }
            }
            if (begin) {
                // 找下级@AliasFor注解
                Collection<AnnotationAttribute<?>> aliasValues = a.getAttributes().values();
                for (AnnotationAttribute<?> am : aliasValues) {
                    if ((memberName.equals(am.getAliasFor()) || am.getAliasFor() == null)
                            && annotationName.equals(am.getAliasForAnnotation())) {
                        Object value = am.getValue();
                        if (value == null) {
                            annotationName = a.getName();
                            memberName = am.getName();
                            lastAttr = am;
                        } else {
                            return (T) value;
                        }
                    }
                }
            }
        }

        if (lastAttr != null) {
            return (T) lastAttr.getDefaultValue();
        }

        return null;
    }
}
